Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Apollo 11 source code released

66 views
Skip to first unread message

JF Mezei

unread,
Jul 10, 2016, 12:43:37 PM7/10/16
to

The source code for many Apollo 11 computers has been released n digital
form on GitHub. (scanned from printed listings at MIT).

https://github.com/chrislgarry/Apollo-11


Question: what computer architecture/instruction set was used for the on
board computers ?

Niklas Holsti

unread,
Jul 10, 2016, 1:33:47 PM7/10/16
to
A custom-made computer:

https://en.wikipedia.org/wiki/Apollo_Guidance_Computer

--
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
. @ .

Fred J. McCall

unread,
Jul 10, 2016, 2:39:51 PM7/10/16
to
Custom.


--
"The reasonable man adapts himself to the world; the unreasonable
man persists in trying to adapt the world to himself. Therefore,
all progress depends on the unreasonable man."
--George Bernard Shaw

JF Mezei

unread,
Jul 10, 2016, 6:28:32 PM7/10/16
to
On 2016-07-10 13:33, Niklas Holsti wrote:

> A custom-made computer:
>
> https://en.wikipedia.org/wiki/Apollo_Guidance_Computer


Very interesting read. Thanks. It mentions it was the first computer
made of integrated circuits. Looks like it was all fixed decimal
notation as opposed to floating point. That would have a big impact on
the heavy math done for guidance and navigation (lots of angles/trig etc).

Was all the code written in assembler or were portions done in higher
level languages ?

Jeff Findley

unread,
Jul 10, 2016, 9:27:56 PM7/10/16
to
In article <5782cc04$0$20011$c3e8da3$1cbc...@news.astraweb.com>,
jfmezei...@vaxination.ca says...
Might be some info in here:

- Chapter Two -
- Computers On Board The Apollo Spacecraft -
The Apollo guidance computer: Hardware
http://history.nasa.gov/computers/Ch2-5.html

If not, I belive there are several books on the subject:

The Apollo Guidance Computer: Architecture and Operation (Springer
Praxis Books)Jul 12, 2010
by Frank O'Brien

Digital Apollo: Human and Machine in SpaceflightApr 4, 2008
by David A. Mindell
Hardcover

Apollo's Computers (Space Book 5)Jun 28, 2014
by Patrick Stakem

Journey to the Moon: The History of the Apollo Guidance Computer
(Library of Flight)Sep 1996
by Eldon C. Hall


Jeff
--
All opinions posted by me on Usenet News are mine, and mine alone.
These posts do not reflect the opinions of my family, friends,
employer, or any organization that I am a member of.

Fred J. McCall

unread,
Jul 11, 2016, 3:36:53 AM7/11/16
to
No HOL. Have you looked at the specifications for these things?

Jeff Findley

unread,
Jul 11, 2016, 6:44:59 AM7/11/16
to
In article <p2j6obt05vvmbg0i0...@4ax.com>,
fjmc...@gmail.com says...
>
> JF Mezei <jfmezei...@vaxination.ca> wrote:
>
> >On 2016-07-10 13:33, Niklas Holsti wrote:
> >
> >> A custom-made computer:
> >>
> >> https://en.wikipedia.org/wiki/Apollo_Guidance_Computer
> >
> >
> >Very interesting read. Thanks. It mentions it was the first computer
> >made of integrated circuits. Looks like it was all fixed decimal
> >notation as opposed to floating point. That would have a big impact on
> >the heavy math done for guidance and navigation (lots of angles/trig etc).
> >
> >Was all the code written in assembler or were portions done in higher
> >level languages ?
> >
>
> No HOL. Have you looked at the specifications for these things?

The Wikipedia entry clearly says this, "AGC software was written in AGC
assembly language and stored on rope memory."

By modern standards, we really don't have much to compare with. Going
back to the 1980's, the AGC was about twice the speed of my old C-64 but
with only a tiny fraction of the RAM and a lot more more ROM (since
there was no other place for program storage like tape or disk).

Putting it in that perspective, the C-64 programs written commercially
rarely used languages above assembly language. You just could not do
much on a C-64 using a "higher level language" due to the overhead of
incurred. Even in the 1980's, compilers, optimizers, and linkers
delivered code which was very "bloated". The 1960's would have been
far, far, worse.

Niklas Holsti

unread,
Jul 11, 2016, 9:20:22 AM7/11/16
to
On 16-07-11 13:44 , Jeff Findley wrote:
> In article <p2j6obt05vvmbg0i0...@4ax.com>,
> fjmc...@gmail.com says...
>>
>> JF Mezei <jfmezei...@vaxination.ca> wrote:
>>
>>> On 2016-07-10 13:33, Niklas Holsti wrote:
>>>
>>>> A custom-made computer:
>>>>
>>>> https://en.wikipedia.org/wiki/Apollo_Guidance_Computer
>>>
>>>
>>> Very interesting read. Thanks. It mentions it was the first computer
>>> made of integrated circuits. Looks like it was all fixed decimal
>>> notation as opposed to floating point. That would have a big impact on
>>> the heavy math done for guidance and navigation (lots of angles/trig etc).
>>>
>>> Was all the code written in assembler or were portions done in higher
>>> level languages ?
>>>
>>
>> No HOL. Have you looked at the specifications for these things?
>
> The Wikipedia entry clearly says this, "AGC software was written in AGC
> assembly language and stored on rope memory."

But the Wikipedia entry also says this:

"The AGC also had a sophisticated software interpreter, developed by the
MIT Instrumentation Laboratory, that implemented a virtual machine with
more complex and capable pseudo-instructions than the native AGC. These
instructions simplified the navigational programs. Interpreted code,
which featured double precision trigonometric, scalar and vector
arithmetic (16 and 24-bit), even an MXV (matrix × vector) instruction,
could be mixed with native AGC code. While the execution time of the
pseudo-instructions was increased (due to the need to interpret these
instructions at runtime) the interpreter provided many more instructions
than AGC natively supported and the memory requirements were much lower
than in the case of adding these instructions to the AGC native language
which would require additional memory built into the computer (at that
time the memory capacity was very expensive). The average
pseudo-instruction required about 24 ms to execute. The assembler and
version control system, named YUL for an early prototype Christmas
Computer,[8] enforced proper transitions between native and interpreted
code."

Reminds me of the SWEET16 VM in the Apple II,
https://en.wikipedia.org/wiki/SWEET16.

JF Mezei

unread,
Jul 11, 2016, 11:53:30 AM7/11/16
to
On 2016-07-11 06:44, Jeff Findley wrote:
> much on a C-64 using a "higher level language" due to the overhead of
> incurred. Even in the 1980's, compilers, optimizers, and linkers
> delivered code which was very "bloated". The 1960's would have been
> far, far, worse.


Not quite. older languages such as COBOL and Fortran provided reasonably
efficient assembly.

When IBM designed the 360 architecture, it had COBOL and FORTRAN in mind
and provided instructiosn to make COBOL more efficient (fixed decimal
math, as well as moving many characters in one operation). The simpler
MOVE command in COBOL could result in a single MVC assembler instruction
if it was a fixed length character field.

However, the Apollo computer instruction set is very basic, so compilers
would not have done a good job of making most efficient code generation.
(not "bloated" but not "most efficient" either

Also, because those computers had direct interfaces to devices/sensors,
those interfaces become easier to managhe in assembler since you have
direct access to memory, registers and interrupts.

The WRITE and READ statements in Fortran would not be well suited for
the type of equipment connected to the computers.

Note: today, things are different because compilers are smart enough to
organise code to make use of various capabilities for the architecture
(pipelining, out of order execution, multiple execution units,
pre-fetching, branch prediction etc).

(However, stuff like object oriented langiuages have so many layers of
bloat that optimization at the machine dode level still leaves it bloated).


If I read correctly, the read-only "rope" memory that contained the
programs had to manually be connected to represent the right bits. This
makes it much easier to work with assembly language since the "compiled"
code with the opcodes/operands in bits can more easily be matched to the
original source code.


Niklas Holsti

unread,
Jul 11, 2016, 7:19:48 PM7/11/16
to
On 16-07-11 18:51 , JF Mezei wrote:
> On 2016-07-11 06:44, Jeff Findley wrote:
>> much on a C-64 using a "higher level language" due to the overhead of
>> incurred. Even in the 1980's, compilers, optimizers, and linkers
>> delivered code which was very "bloated". The 1960's would have been
>> far, far, worse.

How might a 1980's or 1960's linker deliver "bloated code"? In those
days, linkers merely arranged given modules of code in memory and
corrected accordingly the cross-references from one module to another;
linkers did not generate or modify code in other ways.

> Not quite. older languages such as COBOL and Fortran provided reasonably
> efficient assembly.
>
> When IBM designed the 360 architecture, it had COBOL and FORTRAN in mind
> and provided instructiosn to make COBOL more efficient (fixed decimal
> math, as well as moving many characters in one operation). The simpler
> MOVE command in COBOL could result in a single MVC assembler instruction
> if it was a fixed length character field.
>
> However, the Apollo computer instruction set is very basic, so compilers
> would not have done a good job of making most efficient code generation.
> (not "bloated" but not "most efficient" either

Hmm. On the other hand, the compiler's search for the most efficient
translation can be easier for a target machine with a very small
instruction set, because the search-space is smaller. Today, using
search-based optimization, one could probably make a compiler that
generates very efficient code for the AGC, given also that an AGC
program cannot be very large.

But in the 1960s, the choice of assembly language (and the somewhat
enhanced virtual-machine interpreted language) was no doubt a
conservative and risk-reducing decision.

> Also, because those computers had direct interfaces to devices/sensors,
> those interfaces become easier to managhe in assembler since you have
> direct access to memory, registers and interrupts.

I don't think that is a major issue. All intermediate-level and
high-level languages used for embedded systems have standard or
implementation-specific means for easy, direct access to memory
locations and memory-mapped registers. In C, one just converts (casts)
the integer address of a memory location into a pointer, through which
the memory location can be read and written. In Ada one can do the same,
but one can also declare the memory location as a variable which has a
given address, and access the memory location through this variable,
without using pointer syntax.

> Note: today, things are different because compilers are smart enough to
> organise code to make use of various capabilities for the architecture
> (pipelining, out of order execution, multiple execution units,
> pre-fetching, branch prediction etc).

But the AGC had none of those architectural features, so this ability of
modern compilers cannot have played a role in the decision, then, to use
assembly language for the Apollo missions.

> If I read correctly, the read-only "rope" memory that contained the
> programs had to manually be connected to represent the right bits. This
> makes it much easier to work with assembly language since the "compiled"
> code with the opcodes/operands in bits can more easily be matched to the
> original source code.

I don't understand your reasoning here. Yes, the relationship between
assembly language source-code and bits in memory is more direct than for
higher-level languages, but for the AGC the rope-weaving was done by
dedicated staff, not by the programmers, so from the programmers' point
of view the only difference wrt the present-day method of automatically
transferring the assembler's output into a FLASH memory is that the
manual programming took longer and cost more.

Using assembly language may have made it easier to make local changes to
the program in such a way that only some of the "ropes" had to be
rewoven. Even today the maintenance of on-board spacecraft SW may
require that changes are made by local binary patches and not by
uploading a whole new software binary. If the SW is compiled into binary
from a high-level language, it may be difficult to control the compiler
so that a local change in the source language produces only a local
change in the binary, and not, say, a shifting of a large number of
binary instructions forwards or backwards in memory, which would require
a large patch.

Alain Fournier

unread,
Jul 11, 2016, 7:43:35 PM7/11/16
to
Le Jul/11/2016 à 6:44 AM, Jeff Findley a écrit :
> In article <p2j6obt05vvmbg0i0...@4ax.com>,
> fjmc...@gmail.com says...
>>
>> JF Mezei <jfmezei...@vaxination.ca> wrote:
>>
>>> On 2016-07-10 13:33, Niklas Holsti wrote:
>>>
>>>> A custom-made computer:
>>>>
>>>> https://en.wikipedia.org/wiki/Apollo_Guidance_Computer
>>>
>>>
>>> Very interesting read. Thanks. It mentions it was the first computer
>>> made of integrated circuits. Looks like it was all fixed decimal
>>> notation as opposed to floating point. That would have a big impact on
>>> the heavy math done for guidance and navigation (lots of angles/trig etc).
>>>
>>> Was all the code written in assembler or were portions done in higher
>>> level languages ?
>>>
>>
>> No HOL. Have you looked at the specifications for these things?
>
> The Wikipedia entry clearly says this, "AGC software was written in AGC
> assembly language and stored on rope memory."
>
> By modern standards, we really don't have much to compare with. Going
> back to the 1980's, the AGC was about twice the speed of my old C-64 but
> with only a tiny fraction of the RAM and a lot more more ROM (since
> there was no other place for program storage like tape or disk).
>
> Putting it in that perspective, the C-64 programs written commercially
> rarely used languages above assembly language. You just could not do
> much on a C-64 using a "higher level language" due to the overhead of
> incurred.

No, that would be under using the C-64. The 64 in C-64 standed for 64
kilobytes. But that was a little bit of a misnomer. You had 80 kilobytes
of memory. The 64 kb of RAM but also 16 kb of ROM. You had to switch the
16 kb of ROM/RAM to access one or the other. You could save some
precious RAM by using the basic interpreter in the 16 kb of ROM. If I
recall correctly it was a bit on byte number 1 that would be used as a
switch to access the ROM or the underlying RAM. I wrote a program that
could not have fit in 64 kb of RAM, but could be squeezed into the C-64
by switching between the two memory modes. Even then, I had a hard time
making it fit into the memory space. I had to cleverly chose where some
parts of the program were placed in order to have an assembler jump
instruction (a goto if you prefer) at the end of a section of code have
just the right jump address so the next section of code could start with
the last byte of the jump address.
So that was three bytes for the jump instruction, the jump instruction
was one byte and the address where to jump two bytes, therefore it was
jumpto byte1byte2. But the next section of code started with an
instruction, I think it was load into registry, but the important point
is that this instruction's binary code was equal to the byte2 of the
jump instruction, so byte2 was used both as an address where to jump and
as an instruction. It took me a month to figure out how to do it but
that single saved byte allowed me to fit my program in the 80 kb of the
C-64.
Now that I use a computer with 24 Tera-bytes of RAM, I no longer work as
hard to save a single byte.


Alain Fournier

Jeff Findley

unread,
Jul 11, 2016, 8:53:34 PM7/11/16
to
In article <duhkok...@mid.individual.net>,
niklas...@tidorum.invalid says...
The examples given for functionality of the interpreted code bits sound
an awful lot like subroutines.

Jeff Findley

unread,
Jul 11, 2016, 8:58:54 PM7/11/16
to
In article <duinsh...@mid.individual.net>,
niklas...@tidorum.invalid says...
>
> On 16-07-11 18:51 , JF Mezei wrote:
> > On 2016-07-11 06:44, Jeff Findley wrote:
> >> much on a C-64 using a "higher level language" due to the overhead of
> >> incurred. Even in the 1980's, compilers, optimizers, and linkers
> >> delivered code which was very "bloated". The 1960's would have been
> >> far, far, worse.
>
> How might a 1980's or 1960's linker deliver "bloated code"? In those
> days, linkers merely arranged given modules of code in memory and
> corrected accordingly the cross-references from one module to another;
> linkers did not generate or modify code in other ways.

Could linkers of the time recognize duplicate functions (different name,
but functionally identical) and discard the duplicate when linking?
Yes, you can avoid this on a small project with careful software
management, so I'll admit this would be a minor issue.

William Mook

unread,
Jul 11, 2016, 9:28:34 PM7/11/16
to
https://www.youtube.com/watch?v=YIBhPsyYCiM
https://www.youtube.com/watch?v=xQ1O0XR_cA0

Vibrating structure gyros are cheaper and better than Apollo had

http://www.siliconsensing.com/technology/mems-gyroscopes/

So are the computers

https://www.youtube.com/watch?v=gu0Y4vliJcQ

So, its no surprise you could build an AGC for $3,000 in your basement these days

http://gizmodo.com/5319472/how-to-build-the-1mhz-apollo-guidance-computer-for-just-3000

http://www.galaxiki.org/web/main/_blog/all/build-your-own-nasa-apollo-landing-computer-no-kidding.shtml

You can even run an AGC simulator;

http://svtsim.com/moonjs/agc.html

Now, all you need are the checklists - and current ephemeris of the moon, and your precise launch coordinates - and you could launch a Saturn V to the moon and land!

Now, if you take the checklists, and automate them, and then use KEYWORDS to access them in some logical way, you could use a Siri style app that talks to you, and navigates like a mobile map app;

http://www.wired.com/2014/04/out-in-the-open-jasper/

and goes where you want...generating the code to enter for the checklist.

All using GPS and current time, along with the moon position, available via the internet, you could launch a Saturn V from anywhere on Earth to the Moon!

lol.

http://www.mooncalc.org/#/49.495,11.073,5/2016.07.12/12:41/1

Of course, very good simulators exist - that are very instructive as well;

https://www.youtube.com/watch?v=fF4zTkLqHfc

http://www.apolloarchive.com/lander.html

http://eaglelander3d.com

Compare to the NASA simulators;

http://history.nasa.gov/computers/Ch9-2.html

Now, there is a homebuilt 737 that's awesome;

https://www.youtube.com/watch?v=cSiZ3_jy-1w&list=PLE28AAB2EC4DA45EE

I can imagine someone doing a full scale replica of the flight decks of both the Apollo Command module and the Lunar Excursion Module to the same fidelity.

Here's Michael Collins in a simulator

http://inapcache.boston.com/universal/site_graphics/blogs/bigpicture/apollo_07_15/a06_S6938317.jpg

Here's the CM and LEM simulators

https://upload.wikimedia.org/wikipedia/commons/a/a4/Apollo-lunar-simulator.jpg

So, you get in the CM and go through the launch sequence - and the CM and LEM are each on their own six-axis robot arms - like a Fanuc M-2000

http://www.fanuc.eu/bg/en/robots/robot-filter-page/m-2000-series

inside a digital planetarium similar to this Digitalis system

http://www.digitaliseducation.com

The Digitarium is $46,000 - the Fanuc M-2000 is $121,000. The cost of the LEM and CM interiors, faithfully reproduced, and operating seamlessly with the other equipment, about $300,000 each -

http://www.finesportscars.com/finesportscars_i2/cus_car.jpg

So, for about $890,000 - one could build a live action Apollo simulator in about a year.


The way it would work in Earth's one gee field, is you would enter the CM and lie on your back through the launch. The robot arm would shake and toss you to simulate staging as it tilted you to a heads up position moving the CM to the center of the dome. The digital representation outside the window would paint a scene of the SIVB and LEM as the LEM Adapter appeared to float away. As the CM was moved by the robot arm toward the digital image, another robot arm would move a LEM into docking position beneath the full scale projection.

As these building videos show, if you know the properties of the surface you're projecting on, you can compensate and produce amazing effects.

https://www.youtube.com/watch?v=YADbPYJNGOg

So, it would be child's play to project an image of the LEM onto a LEM cabin simulator, so that as you docked with it, the cabin would connect with the CM.

Crew members would then be able to crawl through the tunnel, and into the LEM - on their backs in the LEM as shown in the simulator photo.

The LEM cabin would then be rotated to a stand up position as the CM floated beyond the dome to its tart position. In the end the LEM cabin would be placed atop a fixed descent module simulation sitting in a simulated lunar surface beneath the digitarium dome.

The robot arms simulate vibration in synchrony with the sound tracks and digital projections during firing of the descent engine - to give a sense of the flight. Participants climb out of the lander on to the lunar surface.

The process is reversed to return to Earth with the CM being lowered into a pool of water beneath a dome with the ocean and sky projected on to it.

Discounted at 8.5% per annum, over a ten year period, $890,000 costs $15.74 per hour. For two people, that's $8.00 per person per hour. A 42 minute ride - assuming the vehicle is open 24/7. If open only 42 hours per week, the CAPEX is $32.00 per person - assuming a crew of two. Another $8 per hour - or $4 per person - or $16.00 per person - for OPEX. So, say a 42 minute ride - is $50.00 - and for another $25.00 you can have a video made - and for another $25.00 you can enjoy astronaut food. There's also a video arcade and a restaurant and gift shop - built around the moon museum.





Niklas Holsti

unread,
Jul 12, 2016, 2:24:20 AM7/12/16
to
On 16-07-12 03:58 , Jeff Findley wrote:
> In article <duinsh...@mid.individual.net>,
> niklas...@tidorum.invalid says...
>>
>> On 16-07-11 18:51 , JF Mezei wrote:
>>> On 2016-07-11 06:44, Jeff Findley wrote:
>>>> much on a C-64 using a "higher level language" due to the overhead of
>>>> incurred. Even in the 1980's, compilers, optimizers, and linkers
>>>> delivered code which was very "bloated". The 1960's would have been
>>>> far, far, worse.
>>
>> How might a 1980's or 1960's linker deliver "bloated code"? In those
>> days, linkers merely arranged given modules of code in memory and
>> corrected accordingly the cross-references from one module to another;
>> linkers did not generate or modify code in other ways.
>
> Could linkers of the time recognize duplicate functions (different name,
> but functionally identical) and discard the duplicate when linking?

Good point, I didn't even know that some linkers can do that today. This
optimisation seems to be motivated mainly by multiple auto-instantiation
of C++ templates, but it seems to me that intensive use of
assembly-language macros could have the same code-duplicating effect.

I'll have to check if the linker I'm using does that; I may want to
prevent it so that functions with identical machine code, but used for
different purposes, can be patched independently if necessary.

> Yes, you can avoid this on a small project with careful software
> management, so I'll admit this would be a minor issue.

On the other hand, one of the film documentaries referenced from the
Wikipedia entry says that when the Apollo AGC SW development got into
schedule problems and code-size problems, a trouble-shooter from NASA
found much duplicated code. That can easily happen in a rush project
with multiple programmers.

Fred J. McCall

unread,
Jul 12, 2016, 12:43:40 PM7/12/16
to
JF Mezei <jfmezei...@vaxination.ca> wrote:

>On 2016-07-11 06:44, Jeff Findley wrote:
>> much on a C-64 using a "higher level language" due to the overhead of
>> incurred. Even in the 1980's, compilers, optimizers, and linkers
>> delivered code which was very "bloated". The 1960's would have been
>> far, far, worse.
>>
>
>Not quite. older languages such as COBOL and Fortran provided reasonably
>efficient assembly.
>

For some definition of "reasonably efficient" that equates to 'bloated
when compared to pure assembly'.

<snip irrelevancies>

>
>Note: today, things are different because compilers are smart enough to
>organise code to make use of various capabilities for the architecture
>(pipelining, out of order execution, multiple execution units,
>pre-fetching, branch prediction etc).
>

Some are, some aren't. You realize there are still people who write
assembly for good reason, right?

>
>(However, stuff like object oriented langiuages have so many layers of
>bloat that optimization at the machine dode level still leaves it bloated).
>

So in your view compilers are very clever, but not very clever?

>
>If I read correctly, the read-only "rope" memory that contained the
>programs had to manually be connected to represent the right bits. This
>makes it much easier to work with assembly language since the "compiled"
>code with the opcodes/operands in bits can more easily be matched to the
>original source code.
>

What?


--
"Ordinarily he is insane. But he has lucid moments when he is
only stupid."
-- Heinrich Heine

Fred J. McCall

unread,
Jul 12, 2016, 1:05:01 PM7/12/16
to
Niklas Holsti <niklas...@tidorum.invalid> wrote:

>On 16-07-11 18:51 , JF Mezei wrote:
>> On 2016-07-11 06:44, Jeff Findley wrote:
>>> much on a C-64 using a "higher level language" due to the overhead of
>>> incurred. Even in the 1980's, compilers, optimizers, and linkers
>>> delivered code which was very "bloated". The 1960's would have been
>>> far, far, worse.
>
>How might a 1980's or 1960's linker deliver "bloated code"? In those
>days, linkers merely arranged given modules of code in memory and
>corrected accordingly the cross-references from one module to another;
>linkers did not generate or modify code in other ways.
>

Think RTOS and RTL inclusion in the link...

Fred J. McCall

unread,
Jul 12, 2016, 1:10:31 PM7/12/16
to
Niklas Holsti <niklas...@tidorum.invalid> wrote:

>On 16-07-12 03:58 , Jeff Findley wrote:
>> In article <duinsh...@mid.individual.net>,
>> niklas...@tidorum.invalid says...
>>>
>>> On 16-07-11 18:51 , JF Mezei wrote:
>>>> On 2016-07-11 06:44, Jeff Findley wrote:
>>>>> much on a C-64 using a "higher level language" due to the overhead of
>>>>> incurred. Even in the 1980's, compilers, optimizers, and linkers
>>>>> delivered code which was very "bloated". The 1960's would have been
>>>>> far, far, worse.
>>>
>>> How might a 1980's or 1960's linker deliver "bloated code"? In those
>>> days, linkers merely arranged given modules of code in memory and
>>> corrected accordingly the cross-references from one module to another;
>>> linkers did not generate or modify code in other ways.
>>
>> Could linkers of the time recognize duplicate functions (different name,
>> but functionally identical) and discard the duplicate when linking?
>
>Good point, I didn't even know that some linkers can do that today. This
>optimisation seems to be motivated mainly by multiple auto-instantiation
>of C++ templates, but it seems to me that intensive use of
>assembly-language macros could have the same code-duplicating effect.
>

The part of the linker that takes care of pipelining will recognize
the two identical code sequences.

>
>I'll have to check if the linker I'm using does that; I may want to
>prevent it so that functions with identical machine code, but used for
>different purposes, can be patched independently if necessary.
>

Not an issue unless you're doing binary patches to runtime objects. If
you're doing that, you've got bigger problems than this. If you
relink on a 'patch', the linker will now recognize that the two
routines are different.

JF Mezei

unread,
Jul 12, 2016, 2:36:43 PM7/12/16
to
On 2016-07-11 20:53, Jeff Findley wrote:

> The examples given for functionality of the interpreted code bits sound
> an awful lot like subroutines.

The instruction set contained an almost explicit "call" opcode (which
stores address of next instruction in a register, then branches to
address specified as opcode. Many instructions later, you branch to that
register's address and continue where the "call" left off.



JF Mezei

unread,
Jul 12, 2016, 2:41:46 PM7/12/16
to
On 2016-07-11 20:58, Jeff Findley wrote:

> Could linkers of the time recognize duplicate functions (different name,
> but functionally identical) and discard the duplicate when linking?

No. and I doubt that current linkers do. They will detect duplicate
function definitions.

And back then, there were no architecture specific optimizers such as
GEM which is common now. (compiler generates "pseudo assembler", feeds
it to GEM which is the one which geerates assembly code specific for and
optimized for that architecture).

Where early linkers did work no longer necessary is workout overlays.
When you have limited memory, different subroutines/modules would be
linked with the same memory addresses. But only one would be loaded at a
time, and on sime systems this unloading of one module and loading of
next was automatic (and slow). *(think of it as poor man's virtual memory).

In various Apollo themed movies/TV series, you often hear about "loading
program 64" and this is likely what happened.

Niklas Holsti

unread,
Jul 12, 2016, 4:26:35 PM7/12/16
to
On 16-07-12 21:41 , JF Mezei wrote:
> On 2016-07-11 20:58, Jeff Findley wrote:
>
>> Could linkers of the time recognize duplicate functions (different name,
>> but functionally identical) and discard the duplicate when linking?
>
> No. and I doubt that current linkers do. They will detect duplicate
> function definitions.

Here is the reference I found after Jeff's post, from 2005:
http://blog.vladimirprus.com/2005/03/duplicate-function-bodies.html

Quote: "A couple of days ago I've learned that the Microsoft linker can
merge functions with binary identical bodies." Link:
https://blogs.msdn.microsoft.com/oldnewthing/20050322-00/?p=36113/

> Where early linkers did work no longer necessary is workout overlays.

That linker feature is still used in some small systems where the
architecture limits the address size but applications need more memory,
so the memory is "paged" or "mapped" or "banked" dynamically. Say, the
architectural address is 16 bits but there is 1 MiB of memory (RAM, not
disk) with a 20-bit physical address. The processor then provides 4
"extension" or "mapping" bits that can be set to view different parts of
the memory through the 16-bit, 64 KiB windows. Well, usually the low end
of the memory address is not mapped, so that some core code is visible
in all mappings.

Many current Intel-8051 microcontrollers (8-bit or 16-bit architectural
address) use this kind of memory "overlay". Atmel's 8-bit AVR
architecture also has such features, IIRC.

On the Modcomp IV minicomputer this was actually called "virtual memory"
and used as such: each program/process had a 16-bit "virtual" address
space but several programs/processes could be loaded at once into the
larger physical memory.

> When you have limited memory, different subroutines/modules would be
> linked with the same memory addresses. But only one would be loaded at a
> time, and on sime systems this unloading of one module and loading of
> next was automatic (and slow). *(think of it as poor man's virtual memory).

In the paged/mapped "overlay" systems, "loading" an overlay just means
changing the address-extension/mapping bits, so its very fast. (But some
linkers can/could be very slow at finding a workable overlay structure
automatically. I remember an HP brochure for the HP21MX computers, with
a 16-bit basic address but up to 2 MiB of memory. It quoted linking
times of some number of hours for large, but less than 2 MiB, overlaid
applications).

The Wikipedia entry on the AGC mentions three registers which seem to be
a kind of memory-address-extension register: Bank/Fbank, Ebank, and Sbank.

> In various Apollo themed movies/TV series, you often hear about "loading
> program 64" and this is likely what happened.

The AGC had no "mass memory" -- drum or disk -- only the core memory,
which was directly addressable, no "loading" needed. From where would a
program be loaded? This is just a guess, but to me it seems more likely
that "loading a program" meant starting the program and/or bringing it
into "focus" for commands, inputs, and outputs.

Niklas Holsti

unread,
Jul 12, 2016, 4:37:32 PM7/12/16
to
On 16-07-12 03:53 , Jeff Findley wrote:
> In article <duhkok...@mid.individual.net>,
> niklas...@tidorum.invalid says...
>> But the Wikipedia entry also says this:
>>
>> "The AGC also had a sophisticated software interpreter, developed by the
>> MIT Instrumentation Laboratory, that implemented a virtual machine with
>> more complex and capable pseudo-instructions than the native AGC. These
>> instructions simplified the navigational programs. Interpreted code,
>> which featured double precision trigonometric, scalar and vector
>> arithmetic (16 and 24-bit), even an MXV (matrix × vector) instruction,
>> could be mixed with native AGC code. While the execution time of the
>> pseudo-instructions was increased (due to the need to interpret these
>> instructions at runtime) the interpreter provided many more instructions
>> than AGC natively supported and the memory requirements were much lower
>> than in the case of adding these instructions to the AGC native language
>> which would require additional memory built into the computer (at that
>> time the memory capacity was very expensive)...."
>
> The examples given for functionality of the interpreted code bits sound
> an awful lot like subroutines.

Yes, but the basic AGC instruction set seems IMO very unfriendly to
subroutines -- it is possible to call ("TC", "Transfer Control") a
subroutine and save the return address, but it would be quite difficult
or at least cumbersome to pass arguments, as there are no easy
base+offset addressing modes.

The INDEX instruction can be used to build such addressing modes, but
one base+index computation would take several instructions and at least
one temporary memory location if both "base" and "index" are dynamic
(non-constant) values, as would often be the case for accessing
subroutine arguments that are vectors or arrays.

Fred J. McCall

unread,
Jul 12, 2016, 9:11:27 PM7/12/16
to
That's called a 'subroutine'.


--
"Some people get lost in thought because it's such unfamiliar
territory."
--G. Behn

Fred J. McCall

unread,
Jul 12, 2016, 9:14:25 PM7/12/16
to
Niklas Holsti <niklas...@tidorum.invalid> wrote:

>On 16-07-12 03:53 , Jeff Findley wrote:
>> In article <duhkok...@mid.individual.net>,
>> niklas...@tidorum.invalid says...
>>> But the Wikipedia entry also says this:
>>>
>>> "The AGC also had a sophisticated software interpreter, developed by the
>>> MIT Instrumentation Laboratory, that implemented a virtual machine with
>>> more complex and capable pseudo-instructions than the native AGC. These
>>> instructions simplified the navigational programs. Interpreted code,
>>> which featured double precision trigonometric, scalar and vector
>>> arithmetic (16 and 24-bit), even an MXV (matrix в vector) instruction,
>>> could be mixed with native AGC code. While the execution time of the
>>> pseudo-instructions was increased (due to the need to interpret these
>>> instructions at runtime) the interpreter provided many more instructions
>>> than AGC natively supported and the memory requirements were much lower
>>> than in the case of adding these instructions to the AGC native language
>>> which would require additional memory built into the computer (at that
>>> time the memory capacity was very expensive)...."
>>
>> The examples given for functionality of the interpreted code bits sound
>> an awful lot like subroutines.
>
>Yes, but the basic AGC instruction set seems IMO very unfriendly to
>subroutines -- it is possible to call ("TC", "Transfer Control") a
>subroutine and save the return address, but it would be quite difficult
>or at least cumbersome to pass arguments, as there are no easy
>base+offset addressing modes.
>
>The INDEX instruction can be used to build such addressing modes, but
>one base+index computation would take several instructions and at least
>one temporary memory location if both "base" and "index" are dynamic
>(non-constant) values, as would often be the case for accessing
>subroutine arguments that are vectors or arrays.
>

Easy enough to use something like FORTRAN Common to fake this.

Jeff Findley

unread,
Jul 12, 2016, 9:41:57 PM7/12/16
to
In article <578539e9$0$18125$c3e8da3$a909...@news.astraweb.com>,
jfmezei...@vaxination.ca says...
>
> On 2016-07-11 20:58, Jeff Findley wrote:
>
> > Could linkers of the time recognize duplicate functions (different name,
> > but functionally identical) and discard the duplicate when linking?
>
> No. and I doubt that current linkers do. They will detect duplicate
> function definitions.

Actually, I see this all the time in C++ when you define a pure virtual
interface function in a base class (A) and then have the same
implementation for two derived classes (B and C). For the names given
in parenthesis, when debugging, the debugger will only show the
implementation of that function for B even when called on an object of
type C. Dead giveaway that the linker has discarded the duplicate
implementation.

Niklas Holsti

unread,
Jul 13, 2016, 1:54:04 AM7/13/16
to
On 16-07-13 04:41 , Jeff Findley wrote:
> In article <578539e9$0$18125$c3e8da3$a909...@news.astraweb.com>,
> jfmezei...@vaxination.ca says...
>>
>> On 2016-07-11 20:58, Jeff Findley wrote:
>>
>>> Could linkers of the time recognize duplicate functions (different name,
>>> but functionally identical) and discard the duplicate when linking?
>>
>> No. and I doubt that current linkers do. They will detect duplicate
>> function definitions.
>
> Actually, I see this all the time in C++ when you define a pure virtual
> interface function in a base class (A) and then have the same
> implementation for two derived classes (B and C). For the names given
> in parenthesis, when debugging, the debugger will only show the
> implementation of that function for B even when called on an object of
> type C. Dead giveaway that the linker has discarded the duplicate
> implementation.

I'm curious, which linker are you using?

Jeff Findley

unread,
Jul 13, 2016, 6:43:33 AM7/13/16
to
In article <dum3bq...@mid.individual.net>,
niklas...@tidorum.invalid says...
Whatever is underneath the covers of Microsoft Dev Studio.

Niklas Holsti

unread,
Jul 13, 2016, 2:01:42 PM7/13/16
to
On 16-07-13 04:14 , Fred J. McCall wrote:
> Niklas Holsti <niklas...@tidorum.invalid> wrote:
>
>> On 16-07-12 03:53 , Jeff Findley wrote:
>>> In article <duhkok...@mid.individual.net>,
>>> niklas...@tidorum.invalid says...
>>>> But the Wikipedia entry also says this:
>>>>
>>>> "The AGC also had a sophisticated software interpreter, developed by the
>>>> MIT Instrumentation Laboratory, that implemented a virtual machine with
>>>> more complex and capable pseudo-instructions than the native AGC. These
>>>> instructions simplified the navigational programs. Interpreted code,
>>>> which featured double precision trigonometric, scalar and vector
>>>> arithmetic (16 and 24-bit), even an MXV (matrix × vector) instruction,
>>>> could be mixed with native AGC code. While the execution time of the
>>>> pseudo-instructions was increased (due to the need to interpret these
>>>> instructions at runtime) the interpreter provided many more instructions
>>>> than AGC natively supported and the memory requirements were much lower
>>>> than in the case of adding these instructions to the AGC native language
>>>> which would require additional memory built into the computer (at that
>>>> time the memory capacity was very expensive)...."
>>>
>>> The examples given for functionality of the interpreted code bits sound
>>> an awful lot like subroutines.
>>
>> Yes, but the basic AGC instruction set seems IMO very unfriendly to
>> subroutines -- it is possible to call ("TC", "Transfer Control") a
>> subroutine and save the return address, but it would be quite difficult
>> or at least cumbersome to pass arguments, as there are no easy
>> base+offset addressing modes.
>>
>> The INDEX instruction can be used to build such addressing modes, but
>> one base+index computation would take several instructions and at least
>> one temporary memory location if both "base" and "index" are dynamic
>> (non-constant) values, as would often be the case for accessing
>> subroutine arguments that are vectors or arrays.
>>
>
> Easy enough to use something like FORTRAN Common to fake this.

Fortran Common areas are global variables, not subroutine arguments that
can point to different variables on each call.

Niklas Holsti

unread,
Jul 13, 2016, 2:07:19 PM7/13/16
to
That is exactly the reason for my concern. Because of limited uplink
bandwidth, on-board SW is still often repaired or modified by local
patches to the binary in EEPROM or RAM.

Niklas Holsti

unread,
Jul 13, 2016, 2:08:58 PM7/13/16
to
On 16-07-13 13:43 , Jeff Findley wrote:
> In article <dum3bq...@mid.individual.net>,
> niklas...@tidorum.invalid says...
>>
>> On 16-07-13 04:41 , Jeff Findley wrote:
>>> In article <578539e9$0$18125$c3e8da3$a909...@news.astraweb.com>,
>>> jfmezei...@vaxination.ca says...
>>>>
>>>> On 2016-07-11 20:58, Jeff Findley wrote:
>>>>
>>>>> Could linkers of the time recognize duplicate functions (different name,
>>>>> but functionally identical) and discard the duplicate when linking?
>>>>
>>>> No. and I doubt that current linkers do. They will detect duplicate
>>>> function definitions.
>>>
>>> Actually, I see this all the time in C++ when you define a pure virtual
>>> interface function in a base class (A) and then have the same
>>> implementation for two derived classes (B and C). For the names given
>>> in parenthesis, when debugging, the debugger will only show the
>>> implementation of that function for B even when called on an object of
>>> type C. Dead giveaway that the linker has discarded the duplicate
>>> implementation.
>>
>> I'm curious, which linker are you using?
>
> Whatever is underneath the covers of Microsoft Dev Studio.

So probably the Microsoft linker. That agrees with the weblinks I found
earlier. Apparently the GNU linker is not doing it, which is a relief to me.

Fred J. McCall

unread,
Jul 13, 2016, 11:06:36 PM7/13/16
to
Niklas Holsti <niklas...@tidorum.invalid> wrote:

>On 16-07-13 04:14 , Fred J. McCall wrote:
>> Niklas Holsti <niklas...@tidorum.invalid> wrote:
>>
>>> On 16-07-12 03:53 , Jeff Findley wrote:
>>>> In article <duhkok...@mid.individual.net>,
>>>> niklas...@tidorum.invalid says...
>>>>> But the Wikipedia entry also says this:
>>>>>
>>>>> "The AGC also had a sophisticated software interpreter, developed by the
>>>>> MIT Instrumentation Laboratory, that implemented a virtual machine with
>>>>> more complex and capable pseudo-instructions than the native AGC. These
>>>>> instructions simplified the navigational programs. Interpreted code,
>>>>> which featured double precision trigonometric, scalar and vector
>>>>> arithmetic (16 and 24-bit), even an MXV (matrix в vector) instruction,
>>>>> could be mixed with native AGC code. While the execution time of the
>>>>> pseudo-instructions was increased (due to the need to interpret these
>>>>> instructions at runtime) the interpreter provided many more instructions
>>>>> than AGC natively supported and the memory requirements were much lower
>>>>> than in the case of adding these instructions to the AGC native language
>>>>> which would require additional memory built into the computer (at that
>>>>> time the memory capacity was very expensive)...."
>>>>
>>>> The examples given for functionality of the interpreted code bits sound
>>>> an awful lot like subroutines.
>>>
>>> Yes, but the basic AGC instruction set seems IMO very unfriendly to
>>> subroutines -- it is possible to call ("TC", "Transfer Control") a
>>> subroutine and save the return address, but it would be quite difficult
>>> or at least cumbersome to pass arguments, as there are no easy
>>> base+offset addressing modes.
>>>
>>> The INDEX instruction can be used to build such addressing modes, but
>>> one base+index computation would take several instructions and at least
>>> one temporary memory location if both "base" and "index" are dynamic
>>> (non-constant) values, as would often be the case for accessing
>>> subroutine arguments that are vectors or arrays.
>>>
>>
>> Easy enough to use something like FORTRAN Common to fake this.
>
>Fortran Common areas are global variables, not subroutine arguments that
>can point to different variables on each call.
>

Yes, I know. Here's how it would work. Suppose I have three
parameters, A, B, and C, for a function, X. You build X to read the
three values from some shared area (those 'global variables'). Right
before a call to X, the caller sets the values of the three parameters
in Common to the values desired. X reads those values and runs with
them, changes them if that is desire behaviour, writes a functional
return value to Common, whatever. When X returns, the caller go reads
the values X set and moves on. Rinse and repeat. The only difference
is that instead of the compiler managing everything on the stack frame
for you and having rules about whether you're calling by reference or
by value, you do all that manually around the call to X.

This is dirt simple to do. I shouldn't have to explain it.


--
"Adrenaline is like exercise, but without the excessive gym fees."
-- Professor Walsh, "Buffy the Vampire Slayer"

Fred J. McCall

unread,
Jul 13, 2016, 11:08:33 PM7/13/16
to
So you already have so many horrible problems that you probably
haven't even thought about from doing this that you don't need to
worry about duplicate functions.

Jeff Findley

unread,
Jul 14, 2016, 6:44:43 AM7/14/16
to
In article <200eob9fi8bb0fcuc...@4ax.com>,
fjmc...@gmail.com says...
Agreed. We're talking about programming for a primitive computer with
very little RAM. You do what you have to do to get the job done with
the memory available to you. Which means you have to hand code all of
this yourself. You can't afford for compiled code to cause the computer
to run out of memory during flight, so you have to manage it yourself.

JF Mezei

unread,
Jul 14, 2016, 11:25:37 AM7/14/16
to
On 2016-07-12 13:10, Fred J. McCall wrote:

> The part of the linker that takes care of pipelining will recognize
> the two identical code sequences.

A linker does no such thing. It replaces external references with
resolved addresses of such references, and builds an image file with the
right header for that platform. It does no code optimization or
elimination. It will detect multiple definitions of the same external
name (for instance, if your link includes 2 compilation modules (.obj
files) that have the same subroutine NAME defined.


Not that today's environment usually hides the linker portion and makes
things more confusing. Back then, the link was a separate application
that was explicitelyt called with a list of modules to include and
various option on how to resolve external references.

JF Mezei

unread,
Jul 14, 2016, 11:34:32 AM7/14/16
to
On 2016-07-12 21:41, Jeff Findley wrote:

> Actually, I see this all the time in C++ when you define a pure virtual
> interface function in a base class (A) and then have the same
> implementation for two derived classes (B and C). For the names given
> in parenthesis, when debugging, the debugger will only show the
> implementation of that function for B even when called on an object of
> type C. Dead giveaway that the linker has discarded the duplicate
> implementation.


Such obtimizatiosn are done by the compiler, not the linker. And in a
object oriented language, the compiler does all the stuff to convert the
"object" stuff into procedural code, ( which subroutine to call when you
invoke a method etc). And when the compiler realises that subroutine X
is never called, it doesn't include it in the obvect module because it
is optimized away.

If you compile with a switch to "do not optimize" you will see your code
much more clearly.

In this context, assembly language is not optimized (generally). There
may be macros that are expanded into multiple assembly instructions, but
that is the extent of changes done by the assembler.

There is an exception: the VAX "MACRO" assembly language was implemented
as a compiled language on Alpha and Itanium (and soon x86). As such, the
VAX instructions are sent through optimization during compilation (the
GEM phase of compilation). This is especially true of the Itanium thing
since the chip was very inefficient and required compilers to re-arange
stuff.

Of course, back in the 60s, this didn't happen much. And in the specific
case of th Apollo software, I reckon they did not want any such
optimizations. When they ran the assembler, it wasn't to produce a
binary object file, it was to produce a opcode"/operand listing that the
people doing the hard wiring could use to know how to wire the "rope"
memory.

JF Mezei

unread,
Jul 14, 2016, 11:38:19 AM7/14/16
to

>>Fortran Common areas are global variables, not subroutine arguments that
>>can point to different variables on each call.


One register for the return address. One register contains address of
memory where a list of arguments is stored. So the subroutine looks at
that register and goes out to pick arguments as needed.

Normally, an architecture has a calling standard that defines which
register to use for that. (and which registers to put the return value
before you return control to the calling code.


Snidely

unread,
Jul 14, 2016, 12:12:37 PM7/14/16
to
Jeff Findley formulated the question :
The description as quoted is insufficient to distinguish between a
"subroutine-ish" stored program and a microcode implementation, but the
former is more likely. Note that C64 and Apple II did their BASIC
implementations this way (ROM subroutines), and Forth and Pascal were
available as add-in boards. You could also think of the IBM-PC BIOS in
this way, too.

I understand the IBM 360 was an example of a computer using microcode
where the microcode could be changed in the field. Microcode
essentially provides a virtual machine written on top of a very dumb
and very fast "inner processor". This is still used in x86
architectures, as well as having been part of PDP-11 and VAX building.
The PDP-11 is rumored to have used the PDP-8 cpu/alu design to
implement the "inner processor".

(comment for the other branch of this thread: compiler designers did a
lot of learning about optimization in the 1980s and 1990s)

/dps


--
There's nothing inherently wrong with Big Data. What matters, as it
does for Arnold Lund in California or Richard Rothman in Baltimore, are
the questions -- old and new, good and bad -- this newest tool lets us
ask. (R. Lerhman, CSMonitor.com)

Niklas Holsti

unread,
Jul 15, 2016, 3:26:46 PM7/15/16
to
On 16-07-14 06:06 , Fred J. McCall wrote:
> Niklas Holsti <niklas...@tidorum.invalid> wrote:
>
>> On 16-07-13 04:14 , Fred J. McCall wrote:
>>> Niklas Holsti <niklas...@tidorum.invalid> wrote:
>>>
>>>> On 16-07-12 03:53 , Jeff Findley wrote:
>>>>> In article <duhkok...@mid.individual.net>,
>>>>> niklas...@tidorum.invalid says...
>>>>>> But the Wikipedia entry also says this:
>>>>>>
>>>>>> "The AGC also had a sophisticated software interpreter, developed by the
>>>>>> MIT Instrumentation Laboratory, that implemented a virtual machine with
>>>>>> more complex and capable pseudo-instructions than the native AGC. These
>>>>>> instructions simplified the navigational programs. Interpreted code,
>>>>>> which featured double precision trigonometric, scalar and vector
>>>>>> arithmetic (16 and 24-bit), even an MXV (matrix × vector) instruction,
Of course I know that global variables can be used to pass data into and
out of subroutines, by copy-in and copy-out. I did not claim that
subroutines are impossible on the AGC.

The problem is that the AGC has no register-indirect addressing mode, so
pass-by-reference (pointers) is difficult, and the code to copy
parameter values in and result values out is long and slow.

If the calling sequence is as long as the subroutine being called, there
is no advantage to having a subroutine. This is independent of whether
you write that code manually or have a compiler doing it.

You can use a memory location as a pointer, by the INDEX instruction,
but this is very clumsy compared to the register-based indirect
addressing modes in later computers.

The AGC HW architecture is so spartan that I well understand why they
developed an interpretive virtual machine on top of it.

Niklas Holsti

unread,
Jul 15, 2016, 3:39:38 PM7/15/16
to
On 16-07-14 18:25 , JF Mezei wrote:
> On 2016-07-12 13:10, Fred J. McCall wrote:
>
>> The part of the linker that takes care of pipelining will recognize
>> the two identical code sequences.
>
> A linker does no such thing. It replaces external references with
> resolved addresses of such references, and builds an image file with the
> right header for that platform. It does no code optimization or
> elimination.

Some current linkers do link-time optimization (LTO):

https://en.wikipedia.org/wiki/Interprocedural_optimization
https://en.wikipedia.org/wiki/GNU_Compiler_Collection#Optimization

LTO is sometimes a problem in benchmarks: if all the input data to the
benchmark are embedded in the source code, even hidden in a function of
its own, the compiler + linker can execute all or most of the benchmark
computation at compilation + linking time, as constant-folding
optimization, and no "benchmark code" is left for measuring the
performance...

Even before LTO, linkers for some architectures did "relaxation" which
optimized certain instructions such as jump instructions, choosing the
"shortest" or "nearest" form of jump instruction that can reach from the
jump instruction to the target address.

https://en.wikipedia.org/wiki/Linker_(computing)#Relaxation

Niklas Holsti

unread,
Jul 15, 2016, 4:06:52 PM7/15/16
to
On 16-07-14 18:34 , JF Mezei wrote:

> And in the specific
> case of the Apollo software, I reckon they did not want any such
> optimizations. When they ran the assembler, it wasn't to produce a
> binary object file,

I am pretty sure that the AGC SW developers tested their SW on AGC
simulators before the SW was committed to rope memory. Those SW
simulators would naturally read a binary object file produced by the
assembler.

> it was to produce a opcode"/operand listing that the
> people doing the hard wiring could use to know how to wire the "rope"
> memory.

The film "Computer for Apollo" linked from the Wikipedia AGC entry at
https://www.youtube.com/watch?v=YIBhPsyYCiM, shows (at around 22:15 into
the film) that the rope wiring was semi-automatic: a machine read a
paper tape and then moved an aperture (a small metal ring) to the place
on the core-rope board where the wire should enter a core. The person
working the machine passed the wire through the aperture, the paper tape
advanced, and the aperture moved to the next wire-entry point. The
wiring pattern determined the 0's and 1's of the stored program, and the
paper tape determined the wiring pattern, so the paper tape was IMO
equivalent to a binary object file, although differently encoded.

(The engineers in the film refer to the wiring staff -- adult women --
as "girls". "The girl will then pass the wire..." Weird to hear, today.)

Niklas Holsti

unread,
Jul 15, 2016, 4:54:07 PM7/15/16
to
On 16-07-14 13:44 , Jeff Findley wrote:

> We're talking about programming for a primitive computer with
> very little RAM.

Using global variables as subroutine copy-in/copy-out arguments uses
*more* RAM than passing the arguments by reference would use. But AIUI
the AGC was not friendly to passing by reference.

> You do what you have to do to get the job done with
> the memory available to you. Which means you have to hand code all of
> this yourself. You can't afford for compiled code to cause the computer
> to run out of memory during flight, so you have to manage it yourself.

No you don't. Compilers are used routinely to create code for machines
with tiny or small amounts of RAM. As long as you avoid using the heap
(and, if necessary, tell the compiler not to use the heap implicitly),
and avoid other dynamic memory usage like recursion, the RAM usage can
be computed before flight and the SW will not run out of memory during
flight.

Of course, there are still cases in which compiler-generated code does
not fit into the RAM you have, but manually written assembly-language
code fits. But these cases are very rare today -- compilers for embedded
systems can do astonishing optimizations to save on RAM, things an
assembly-language programmer would almost never dare do because they
would be too difficult to maintain as the SW evolves.

I don't know whether a useful compiler could have been created for the
AGC SW. At that time, assembly-language programming was the default
choice for embedded systems, I believe, so perhaps the question was not
even studied. Moreover, perhaps the AGC architecture was evolving so
rapidly that no compiler developers could have kept up.

Niklas Holsti

unread,
Jul 15, 2016, 5:10:32 PM7/15/16
to
On 16-07-14 18:38 , JF Mezei wrote:
>
>>> Fortran Common areas are global variables, not subroutine arguments that
>>> can point to different variables on each call.
>
>
> One register for the return address.

That is the Q register in the AGC.

> One register contains address of
> memory where a list of arguments is stored.

And which register is this, on the AGC? The AGC had a very small number
of registers, and no register that could be directly used as a pointer.

> So the subroutine looks at that register and goes out to pick
> arguments as needed.

With no register-indirect addressing modes, that is quite cumbersome.
Can be done, of course, with some effort and cost in time and space.

> Normally, an architecture has a calling standard that defines which
> register to use for that. (and which registers to put the return value
> before you return control to the calling code.

Today, yes, but today's computers have rather more registers, and more
addressing modes, than the AGC had. All AGC computations used the single
accumulator register (A) and a couple of auxiliary registers (Q, LP) for
division and multiplication. Any further argument-passing had to be done
through RAM. And of course there was no HW-supported stack, so
subroutines probably kept their local variables in statically allocated
RAM locations.

Jeff Findley

unread,
Jul 15, 2016, 7:48:12 PM7/15/16
to
In article <5787b105$0$34695$c3e8da3$dbd...@news.astraweb.com>,
jfmezei...@vaxination.ca says...
>
> On 2016-07-12 21:41, Jeff Findley wrote:
>
> > Actually, I see this all the time in C++ when you define a pure virtual
> > interface function in a base class (A) and then have the same
> > implementation for two derived classes (B and C). For the names given
> > in parenthesis, when debugging, the debugger will only show the
> > implementation of that function for B even when called on an object of
> > type C. Dead giveaway that the linker has discarded the duplicate
> > implementation.
>
>
> Such obtimizatiosn are done by the compiler, not the linker. And in a
> object oriented language, the compiler does all the stuff to convert the
> "object" stuff into procedural code, ( which subroutine to call when you
> invoke a method etc). And when the compiler realises that subroutine X
> is never called, it doesn't include it in the obvect module because it
> is optimized away.

How could this possibly be done in the compiler when the code I'm
talking about is written such that each class has its own .cxx file
which is compiled *separately* into individual object files?

Jeff Findley

unread,
Jul 15, 2016, 7:59:10 PM7/15/16
to
In article <MPG.31f340409...@news.eternal-september.org>,
jfin...@cinci.nospam.rr.com says...
>
> In article <5787b105$0$34695$c3e8da3$dbd...@news.astraweb.com>,
> jfmezei...@vaxination.ca says...
> >
> > On 2016-07-12 21:41, Jeff Findley wrote:
> >
> > > Actually, I see this all the time in C++ when you define a pure virtual
> > > interface function in a base class (A) and then have the same
> > > implementation for two derived classes (B and C). For the names given
> > > in parenthesis, when debugging, the debugger will only show the
> > > implementation of that function for B even when called on an object of
> > > type C. Dead giveaway that the linker has discarded the duplicate
> > > implementation.
> >
> >
> > Such obtimizatiosn are done by the compiler, not the linker. And in a
> > object oriented language, the compiler does all the stuff to convert the
> > "object" stuff into procedural code, ( which subroutine to call when you
> > invoke a method etc). And when the compiler realises that subroutine X
> > is never called, it doesn't include it in the obvect module because it
> > is optimized away.
>
> How could this possibly be done in the compiler when the code I'm
> talking about is written such that each class has its own .cxx file
> which is compiled *separately* into individual object files?

Microsoft explains exactly what I'm talking about. The linker
(necessarily) does this optimization.

Why does the debugger show me the wrong function?
https://blogs.msdn.microsoft.com/oldnewthing/20050322-00/?p=36113

JF Mezei

unread,
Jul 17, 2016, 11:49:27 AM7/17/16
to
On 2016-07-15 16:54, Niklas Holsti wrote:

> No you don't. Compilers are used routinely to create code for machines
> with tiny or small amounts of RAM. As long as you avoid using the heap
> (and, if necessary, tell the compiler not to use the heap implicitly),

Whether heap is used or not depends on compiler. Older compilers likely
had statically allocated data structures. C did not exist when Apollo
first flew.


> code fits. But these cases are very rare today -- compilers for embedded
> systems can do astonishing optimizations to save on RAM, things an
> assembly-language programmer would almost never dare do because they
> would be too difficult to maintain as the SW evolves.

Apart from optimizing variables away (such as a variable used as a loop
counter which ends up being used in a register only), what sort of other
memory saving techniques exist ?

Also, when you write embedded code with avrous hardware attachements,
you may not want the compiler to optimize away your variables as the
storage may have to be reserved at specific addresses for communications
with devices. (DMA etc).

Device X may end up writing at address A, and device Y then reads from
A. The compiler would think your program never uses the variable at
address A and allocates something else in that location.



> I don't know whether a useful compiler could have been created for the
> AGC SW. At that time, assembly-language programming was the default
> choice for embedded systems,

Did programmed embeded devices exist at that time ? or was the moon shot
the catalyst to develop such computers Considering the memory and
performance constraints, Assembler may have been the only solution.

JF Mezei

unread,
Jul 17, 2016, 12:00:20 PM7/17/16
to
On 2016-07-15 19:59, Jeff Findley wrote:

>> How could this possibly be done in the compiler when the code I'm
>> talking about is written such that each class has its own .cxx file
>> which is compiled *separately* into individual object files?
>
> Microsoft explains exactly what I'm talking about. The linker
> (necessarily) does this optimization.


As objects are hiearchical and inherit capabilities from their parent,
it is quite possible to have a chair call a method "paint chair" and a
table call "paint table". But as those inherit that capability from
their parent "furniture". The compiler would ask the linker to resolve
"paint furniture" for each of those 2 calls to different routine names
in the source code.

C++ and other object oriented stuff is many many layers above assembly
language where memory allocation and branchig and returning to
subroutines is very explicit.



Jeff Findley

unread,
Jul 17, 2016, 12:14:06 PM7/17/16
to
In article <578bab93$0$51821$c3e8da3$f626...@news.astraweb.com>,
jfmezei...@vaxination.ca says...
I've been working with C++ for the last 20 years and hold a job title
commensurate with my 26 years of experience as a software developer. I
don't need to be told how C++ works as I use it every single day as part
of my job.

You, however, ignored my original example completely, have snipped the
link to Microsoft's explanation that I provided, and substituted an
example that is not at all like the one I first gave.

There is no further purpose to engaging you in this thread as you are
being evasive, obtuse, or perhaps both.

JF Mezei

unread,
Jul 17, 2016, 12:56:04 PM7/17/16
to
On 2016-07-17 12:14, Jeff Findley wrote:

> You, however, ignored my original example completely, have snipped the
> link to Microsoft's explanation that I provided, and substituted an
> example that is not at all like the one I first gave.

No. I dodn't ignored. The way I interpreted it was that the linker was
given task to resolve 2 routines which end up pointing to the same routine.

Also remember that the question on MS's web page was about the debugger.
If, at run-time, the debugger displays code for "routine2" when you
step into routine1 means that the COMPILER inserted debugging
instructions in the object module for the debugger run time to display
the roioginal source code associated with the next instruction. So it is
the compiler that would have realised that routine1 and routine2 would
have been identical and the compiler would have opptimized one of the 2
away.

I don't trust Microsoft to ever use the proper terminology and
standards. And in an integrated developper suite, the the line between
compiler, linker and run time debugger are muddled whereas prior to
Microsoft, there were very clear roles for each.

Note that optimizations of code is now done by the compiler, followed by
opti9mizations for platform done by GEM. (compilers now generate pseudo
code and the GEM back end generates platform specific object code with
architecture specific optimizations (pipelining, out of order execution
etc).

This is why normally, when you compile with the /debug option, you also
want /nooptimize in order to have the execution reflect what you wrote.


William Mook

unread,
Jul 17, 2016, 9:42:00 PM7/17/16
to
On Monday, July 18, 2016 at 3:49:27 AM UTC+12, JF Mezei wrote:
> On 2016-07-15 16:54, Niklas Holsti wrote:
>
> Older compilers likely
> had statically allocated data structures.

You got that right! The program was woven into the computer rope memory.

https://www.youtube.com/watch?v=YIBhPsyYCiM

It took about 10,500 keystrokes to carry out a mission.

Today, we not only have better computers, we also have better software and better sensors.

https://www.youtube.com/watch?v=7P12e0WpjPQ

https://www.youtube.com/watch?v=cLTwT36l_U4

https://www.youtube.com/watch?v=A03AENwOVNY

https://www.youtube.com/watch?v=ZUY0w34jBIM

It's rather easy to create a system that can navigate seamlessly without a lot of operator intervention.

The problem has always been propulsion. But advances in that area as well could make a spaceship in every garage possible!

Micro-rockets

https://www.youtube.com/watch?v=Y7IsyjFROHE

http://www.bu.edu/phpbin/news-cms/news/?dept=1127&id=40897&template=226

Adaptation to assembly, coating, fabrication, separation, etc., etc.

https://www.youtube.com/watch?v=r6TGvG7RUyo

Useful for self replicating machinery.

https://www.youtube.com/watch?v=BN-FU8VPoOc


A long-duration biosuit with MEMS based life support

http://www.nasa.gov/pdf/617047main_45s_building_future_spacesuit.pdf

Massing only 15 kg and provides 32 days of support - with full recycling of air and water - using only 12.8 kg of dried consumable materials.

http://www.nss.org/settlement/ColoniesInSpace/fig0903.gif

686 grams of oxygen consumed per day along with 270 grams of hydrocarbons produces 857 grams of CO2 per day and 64 grams of H2O.

702 cc of water broken down into 624 grams of oxygen and 78 grams of hydrogen each day produces sufficient hydrogen when combined with process hydrogen to combine with the 857 grams of CO2 to produce 312 grams of methane and 702cc of water. The CH4 is reduced to 234 grams of Carbon black and 78 grams of hydrogen.

An additional 64 grams of H2O is broken down into 7 grams of hydrogen and 57 grams of oxygen. This is added to the oxygen recovered from the CO2 and rebreathed.

In all 772 cc of water is broken down into 686 grams of oxygen and 86 grams of hydrogen and 312 grams of methane is broken down into 234 grams of carbon black and 78 grams of hydrogen - giving enough hydrogen to absorb 857 grams of CO2 and recycling the oxygen. The cost? 196 Watts! With a hyper efficient solar panel, this requires a 5.3 cm diameter disk in space! A larger collector stays well ahead of the needs for power.

A biosuit equipped with a hyper efficient solar collecting flexible film, easily produces 1200 Watts of power continuously when exposed to sunlight in space near Earth.

http://www.powerfilmsolar.com

With 200 Wh/kg of weight, modern super capacitors massing only 5 kg can supply breathable oxygen from a person's breath for five hours.

http://spectrum.ieee.org/nanoclast/consumer-electronics/portable-devices/holey-graphene-boosts-energy-density-of-supercapacitors

An adult male astronaut will mass on average 90 kg to 150 kg payload is sufficient to meet the needs of a traveller.

It takes 18 km/sec to go to the moon and return - in about 10 hours each way. So, the astronaut can sleep in tansit, and spend 10 to 16 hours on the moon, active before returning - in less than two days.

Using an electrospray rocket with 54 km/sec exhaust speed its easy to see tha 28.35% of the take off weight must be propellant. Assuming no propellant is added on the lunar surface. This means that 210 kg is the take off weight, with 60 kg propellant on board moving a 150 kg payload through 18 km/sec.

To produce 2 gee at lift off requires a thrust of 4119 Newtons (420 kgf). This requires 76.3 grams of propellant per second at lift off to be ejected at 54 km/sec. This requires 111 MW of power be applied to the rocket. This is supplied by a laser beam.

http://lasermotive.com

Which also doubles as a broadband communications system by beam modulation. The suit is equipped with wings which receive the power, and form a spot 2 meters in diameter. An emitter 129 meters in diameter on Earth is sufficient to beam a 2 meter diameter spot 384,400 km distant! Even if only 1/4 of the light is received at the moon, 1/2 gee force can be exerted by the engine - which is 3x that needed to operate in the lunar environment of 1/6 gee.

This is on the order of the OWL Telescope - Overwhelmingly Large Telescope -

https://en.wikipedia.org/wiki/Overwhelmingly_Large_Telescope

The $1.5 billion construction costs, could be reduced using inflatable optics, and building three of them 120 degrees apart in longitude, in the cloud free regions of the planet. When not otherwise used for space operations, the transmitter could double as a large optical telescope!

http://proceedings.spiedigitallibrary.org/proceeding.aspx?articleid=856162

http://www.hindawi.com/journals/ijp/2015/196186/

Increasing the size of the space receiver increases power levels in the suit from sunlight, as well as reducing the size of the Earth bound mirror.

Two 16 meter diameter inflatable mirrors one on Earth and another carried by the astronaut, achieves an efficient transfer of power from Earth to Moon - when operating at 550 nm. (green light). A space based mirror this size also has the capacity to collect 254,868 watts of solar energy! This is sufficient to produce 1/22nd gee during transit. A sizeable amount! Not enough to land, but sufficient amount to navigate without relying upon the terrestrial telescope.

http://phys.org/news/2011-05-scientists-high-efficiency-ceramic-laser.html
http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/20080007132.pdf
http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/20080007132.pdf

https://www.osapublishing.org/DirectPDFAccess/D3C9C14F-94F6-F6CD-D7F907ED6F07785B_294315/oe-22-13-16386.pdf?da=1&id=294315&seq=0&mobile=no

http://princetonoptronics.com/pdfs/93810B_DL.pdf

200 megawatts of electrical power at each location, drives the laser array. When not otherwise used, the power is used to support astronomers at each location.

A 70 m diameter inflatable beam director, on the ground, connecting to a 5 m diameter inflatable receiver in flight - is a nice combination.

Acceleration directly to lunar transfer velocity, arriving at the moon 10 hours later, which then slows the astronaut for direct landing on the lunar surface. It takes about 20 minutes to launch, and another 6 minutes to land. Three an hour - for six hours - projects 18 people to the moon - every day. About $10,000 worth of power. Charging enough to make $20 million per day - generates $7.3 billion per year free cash flow.

One launch laser, one braking laser, and one return laser. Each located in sunny cloud free regions separated by 120 degrees of longitude. Atacama or Great American, Gobi or Thar or Gibson, Kalahari or Sahara or Arabian - all are interesting spots. Mountain tops are also of interest.

Solar power for these sites allow demonstration of important technologies in addition to power beaming. Sending people to the moon and back and maintaining broadband contact, promote the next step, the creation of a power satellite network along with a communications satellite network delivering power and broadband to wherever its needed.

Putting 300 kg modules into orbit, each one capable of collecting and transmitting 6.6 MW of useful energy from orbit, and operating as a single phased array unit at the optical bands, provides a way to expand the capacity of the terrestrial system. Increasing to 11 GW from 0.11 GW increases take off weight from 210 kg to 21,000 kg for lunar operations and module power to 660 MW for power satellite operations.

Swarms of free flying self replicating machines operating on Earth and on the lunar surface, with the ability to refuel on the moon, provide a means to easily move between Earth and moon, and in similar fashion, move around the solar system.

Niklas Holsti

unread,
Jul 18, 2016, 2:20:21 AM7/18/16
to
On 16-07-17 18:49 , JF Mezei wrote:
> On 2016-07-15 16:54, Niklas Holsti wrote:
>
>> No you don't. Compilers are used routinely to create code for machines
>> with tiny or small amounts of RAM. As long as you avoid using the heap
>> (and, if necessary, tell the compiler not to use the heap implicitly),
>
> Whether heap is used or not depends on compiler. Older compilers likely
> had statically allocated data structures. C did not exist when Apollo
> first flew.

The classical languages -- Fortran, Algol, Pascal, Modula, C -- are
designed so that the compiler does not need to use implicit heap
allocation in the generated code. Heap allocation is used only if the
source code says so pretty explicitly.

But you are right that some languages are such that the compiled code is
likely to use, or even required to use heap allocation -- Java comes to
mind. I did not mean to say that no compilers use implicit heap
allocation, so my wording could have been better. But even in Java there
are ways to reduce or avoid heap allocations -- the "real-time" Java
extensions.

>> code fits. But these cases are very rare today -- compilers for embedded
>> systems can do astonishing optimizations to save on RAM, things an
>> assembly-language programmer would almost never dare do because they
>> would be too difficult to maintain as the SW evolves.
>
> Apart from optimizing variables away (such as a variable used as a loop
> counter which ends up being used in a register only), what sort of other
> memory saving techniques exist ?

The Keil compiler for the Intel-8051 architecture has the following
feature (which may also exist in other compilers for all I know).

Like the AGC, the basic 8051 is weak at indirect addressing -- general
register-based indirect addressing and the HW stack are available only
in the 128 or 256 byte (yes, byte!) "internal" memory, and the larger
"external" memory can be addressed indirectly only by one dedicated
register. Therefore, compilers for the 8051 typically allocate memory
locations statically for most subroutine parameters and local variables
(assuming that subroutines are not recursive).

The Keil compiler inspects the whole call-tree, finds out which
subroutines cannot be active at the same time, and makes those
subroutines share the same memory locations for their data. For example,
if subroutine A never calls subroutine B, directly or indirectly, and B
never calls A, directly or indirectly, then the parameters and variables
of A and B can be placed in the same memory locations -- when A needs
them, B does not, and vice versa.

But this global knowledge of the call-tree is something that few
programmers could keep in their heads, for largish programs. And the
manual work of either overlaying or separating the data for two
subroutines, as the call-tree changes during program evolution, would be
costly and error-prone.

> Also, when you write embedded code with avrous hardware attachements,
> you may not want the compiler to optimize away your variables as the
> storage may have to be reserved at specific addresses for communications
> with devices. (DMA etc).

Languages have features like "volatile" for that. Not a problem.

>> I don't know whether a useful compiler could have been created for the
>> AGC SW. At that time, assembly-language programming was the default
>> choice for embedded systems,
>
> Did programmed embeded devices exist at that time ? or was the moon shot
> the catalyst to develop such computers Considering the memory and
> performance constraints, Assembler may have been the only solution.

The 1960's was the decade that invented the minicomputer, although the
early ones were only "mini" in comparison with the mainframes. Looking
only at some examples that were available for the public, we have the
Elliot 803 in 1960 (https://en.wikipedia.org/wiki/Elliott_803), the LINC
in 1962 (https://en.wikipedia.org/wiki/LINC), the Bull Gamma M-40 in
1964 (http://www.feb-patrimoine.com/histoire/english/gamma_m40.htm), and
of course the PDP series with the PDP-8 in 1965
(https://en.wikipedia.org/wiki/PDP-8).

The AGC was remarkable in being small, rugged, and dedicated to a single
application with most of the code in ROM. I would assume that similar
computers were used in military applications, before and after Apollo.

Fred J. McCall

unread,
Jul 20, 2016, 1:40:04 PM7/20/16
to
JF Mezei <jfmezei...@vaxination.ca> wrote:

>On 2016-07-12 13:10, Fred J. McCall wrote:
>
>> The part of the linker that takes care of pipelining will recognize
>> the two identical code sequences.
>
>A linker does no such thing. It replaces external references with
>resolved addresses of such references, and builds an image file with the
>right header for that platform. It does no code optimization or
>elimination. It will detect multiple definitions of the same external
>name (for instance, if your link includes 2 compilation modules (.obj
>files) that have the same subroutine NAME defined.
>

You're ignorant. Educate yourself.

>
>Not that today's environment usually hides the linker portion and makes
>things more confusing. Back then, the link was a separate application
>that was explicitelyt called with a list of modules to include and
>various option on how to resolve external references.
>

And a bunch of options on how to optimize.


--
"Ignorance is preferable to error, and he is less remote from the
truth who believes nothing than he who believes what is wrong."
-- Thomas Jefferson

Fred J. McCall

unread,
Jul 20, 2016, 1:49:11 PM7/20/16
to
No, you claimed "quite difficult". It's not.

>
>The problem is that the AGC has no register-indirect addressing mode, so
>pass-by-reference (pointers) is difficult, and the code to copy
>parameter values in and result values out is long and slow.
>

No. Anything the architecture could have helped you with can be done
manually in software, either implicitly or explicitly. Yes, there
will be minor speed impacts. MINOR speed impacts.

>
>If the calling sequence is as long as the subroutine being called, there
>is no advantage to having a subroutine. This is independent of whether
>you write that code manually or have a compiler doing it.
>

Wrong. There will always be a maintenance advantage.


--
"Some people get lost in thought because it's such unfamiliar
territory."
--G. Behn
0 new messages